package com.woate.wingframework.lang;

import java.io.Serializable;
import java.util.Date;

/**
 * 第8时区日期对象
 *
 * @author woate
 */
public final class FastDate implements Serializable, Cloneable, Comparable<FastDate> {
    /**
     * 一秒所对应的毫秒数
     */
    static final long SECOND = 1000L;
    /**
     * 一分钟对应的毫秒数
     */
    static final long MINUTE = 60 * SECOND;
    /**
     * 一小时对应的毫秒数
     */
    static final long HOUR = 60 * MINUTE;
    /**
     * 一天对应的毫秒数
     */
    static final long DAY = 24 * HOUR;
    /**
     * 平年月份天数表,这是一种最直观理解的做法，
     * 更快的计算方法是将一年的天数直接按照
     * 365，334，。。。，31
     * 这样的倒序数组存放，对当年之前的月份快速失败，以最快的速度找到最后一个月，计算量直接减少
     */
    static int MOUTHTABLE[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    /**
     * 闰年月份天数表
     */
    static int MOUTHTABLE_LEAP[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    static int MOUTHTABLE2[] = {365, 334, 304, 273, 243, 212, 181, 151, 120, 90, 59, 31, 0};
    static int MOUTHTABLE_LEAP2[] = {366, 335, 305, 274, 244, 213, 182, 152, 121, 91, 60, 31, 0};

    long now;
    int timeZone = 0;
    int year;
    int month;
    int day;
    int h;
    int m;
    int s;
    int ss;
    boolean bproc = false;

    public FastDate() {
        this(System.currentTimeMillis(), 8);
    }

    public FastDate(long now) {
        this(now, 8);
    }

    public FastDate(long now, int timeZone) {
        this.timeZone = timeZone;
        this.now = now + timeZone * HOUR;
    }

    void proc() {
        //距离1970年01月01日的天数
        int days = (int) (now / DAY) + 1;
        //计算出的年份
        int year = 1970;
        //计算出的月份
        int month = 0;
        //计算出的天数
        int day = days;
        //当年所经历的天数
        int count = 0;
        boolean leap = false;
        do {
            leap = isLeapYear(year);
            int mouthtable[];
            //以最快速度寻找所在年
            mouthtable = leap ? MOUTHTABLE_LEAP2 : MOUTHTABLE2;
            if (day > mouthtable[0]) {
                ++year;
                count = mouthtable[0];
                day -= mouthtable[0];
                continue;
            }
            count = 0;
            //以下为搜索具体的月份
            for (int i = 0; i < 12; i++) {
                if (day <= mouthtable[i] && day > mouthtable[i + 1]) {
                    month = 11 - i;
                    day -= mouthtable[i + 1];
                    break;
                }
            }
        } while ((!leap && count == 365) || (leap && count == 366));
        long h = now % DAY / HOUR;
        long m = now % HOUR / MINUTE;
        long s = now % MINUTE / SECOND;
        long ss = now % 1000L;
        this.year = year;
        this.month = month + 1;
        this.day = day;
        this.h = (int) h;
        this.m = (int) m;
        this.s = (int) s;
        this.ss = (int) ss;
        this.bproc = true;
    }

    /**
     * 将毫秒数转换为日期字符串
     */
    void proc0() {
        //距离1970年01月01日的天数
        int days = (int) (now / DAY) + 1;
        //计算出的年份
        int year = 1970;
        //计算出的月份
        int month = 1;
        //计算出的天数
        int day = days;
        //当年所经历的天数
        int count = 0;
        boolean leap = false;
        do {
            leap = isLeapYear(year);
            count = 0;
            int mouthtable[];
            int lastMonthDay = 0;
            mouthtable = leap ? MOUTHTABLE_LEAP : MOUTHTABLE;
            for (int i = 0; i < 12; i++) {
                int m = mouthtable[i];
                //试算剩下的天数
                int temp = day - m;
                //如果能够满月，则计算下一个月
                if (temp > 0) {
                    day = temp;
                    count += m;
                } else {//不足，则终止到了最后一个月
                    month = i;
                    break;
                }
            }
            //如果当年满了天数,则新增加一年
            if ((!leap && count == 365) || (leap && count == 366)) {
                ++year;
            }
        } while (count >= 365);
        long h = now % DAY / HOUR;
        long m = now % HOUR / MINUTE;
        long s = now % MINUTE / SECOND;
        long ss = now % 1000L;
        this.year = year;
        this.month = month + 1;
        this.day = day;
        this.h = (int) h;
        this.m = (int) m;
        this.s = (int) s;
        this.ss = (int) ss;
        this.bproc = true;
    }

    public int getYear() {
        return year;
    }

    public int getMonth() {
        return month;
    }

    public int getDay() {
        return day;
    }

    public int getH() {
        return h;
    }

    public int getM() {
        return m;
    }

    public int getS() {
        return s;
    }

    public int getSs() {
        return ss;
    }

    /**
     * 判断是否是闰年
     *
     * @param year
     * @return
     */
    boolean isLeapYear(int year) {
        if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
            return true;
        } else {
            return false;
        }
    }

    public int getTimeZone() {
        return timeZone;
    }

    public String toString(DateStyle dateStyle) {
        return new FastDateFormat().format(this, dateStyle);
    }

    public long getTime() {
        return now - timeZone * HOUR;
    }

    public Date toDate() {
        return new Date(now - timeZone * HOUR);
    }

    /**
     * 输出yyyyMMdddHHmmssSSS这样的字符串
     *
     * @return
     */
    public String toString() {
        return new FastDateFormat().format(this, DateStyle.FILE_FORMAT3);
    }

    public int hashCode() {
        long ht = now;
        return (int) ht ^ (int) (ht >> 32);
    }

    @Override
    public int compareTo(FastDate another) {
        return (now < another.now ? -1 : (now == another.now ? 0 : 1));
    }

    @Override
    public boolean equals(Object obj) {
        FastDate another = (FastDate) obj;
        return now == another.now;
    }

}